
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "CImg.h"
#include "minimal_shader.h"
#include <iostream>

using namespace cimg_library;
//#define cimg_use_png
//float width = 0.1;
//static const GLfloat vertex_list[][3] = {
//  -width, -width, -width,
//  width, -width, -width,
//  -width, width, -width,
//  width, width, -width,
//  -width, -width, width,
//  width, -width, width,
//  -width, width, width,
//  width, width, width,
//};
void  init_fix() {
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //gluOrtho2D(-1.0, 1, -1.0, 1);
    gluPerspective(30, 1, 0.5f, 20.0f); //透视投影
}

void  display_fix() {
    glClear(GL_COLOR_BUFFER_BIT);
    
    glViewport(0, 0,400,400);
    
    glEnable(GL_LINE_STIPPLE);
    GLushort  patn = 0xFAFA;
    //glLineStipple(3, patn);
    glColor3f(1.0, 1.0, 1.0);

    glLineWidth(2.0);
    glBegin(GL_LINE_LOOP);
    glVertex3i(1, -1,0);
    glVertex3f(0, 0,0);
    glVertex3i(0, 1,0);
    glEnd();

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glutSolidCube(2.0f);
    glFlush();
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
GLuint vShader, fShader, programHandle;

GLuint  vaoHandle, vboHandles[2], positionBufferHandle, colorBufferHandle;

GLuint textures[2];

//float positionData[] = { 1.0f, -1.0f, 0.0f,
//-0.999f, -0.999f, 1.0f,
//0.0f, 1.0f, -1.0f };
float positionData[6][8] = { 
        { -1.0, -1.0, 0.0, 1.0, 0.0, 0.0 ,0.0,1.0},//triangles
        { 1.0, -1.0, 0.0, 0.0, 1.0, 0.0,1.0,1.0 },
        { -1.0, 1.0, 0.0, 0.0, 0.0, 1.0 ,0.0,0.0},
        { 1.0, -1.0, 0.0, 0.0, 1.0, 0.0,1.0,1.0 },//triangles
        { 1.0, 1.0, 0.0, 1.0, 1.0, 1.0,1.0,0.0},
        { -1.0, 1.0, 0.0, 0.0, 0.0, 1.0 ,0.0,0.0},
        };

int infoLogLength = 0;
int charWritten = 0;
char *infoLog;

void SetupShader()
{

    char *vs, *fs;
    char *vv, *ff;
    char *txt;

    vShader = glCreateShader(GL_VERTEX_SHADER);

    vs = vert;
    vv = vs;

    glShaderSource(vShader, 1, &vv, NULL);
    glCompileShader(vShader);
    //free(vs);

    /////////////////////////////////////////////////////////////////////////////////
    fShader = glCreateShader(GL_FRAGMENT_SHADER);

    fs =frag;
    ff = fs;
    glShaderSource(fShader, 1, &ff, NULL);
    glCompileShader(fShader);


    {////////////////////////////////////输出shader错误///////////////////////////////
        glGetShaderiv(fShader, GL_INFO_LOG_LENGTH, &infoLogLength);

        if (infoLogLength > 1)
        {
            infoLog = (char *)malloc(infoLogLength);
            glGetShaderInfoLog(fShader, infoLogLength, &charWritten, infoLog);
            ////////charWritten is 
            printf("%s \n", infoLog);
            printf("***********************************************************\n");
            free(infoLog);
        }
    }


    programHandle = glCreateProgram();

    glAttachShader(programHandle, vShader);
    glAttachShader(programHandle, fShader);

    glLinkProgram(programHandle);
    GLint success;
    glGetProgramiv(programHandle,
        GL_LINK_STATUS,
        &success);
    if (!success) {
        printf("Shader could not be linked!\n ");
    }
    //glUseProgram(programHandle);
}

void InitVBO()
{

        glGenBuffers(2, vboHandles);

        positionBufferHandle = vboHandles[0];

        glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);

        glBufferData(GL_ARRAY_BUFFER, sizeof(positionData), positionData, GL_STATIC_DRAW);

        glGenVertexArrays(1, &vaoHandle);

        glBindVertexArray(vaoHandle);

        glEnableVertexAttribArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), NULL);

        glEnableVertexAttribArray(1);

        glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);

        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));

        glEnableVertexAttribArray(2);

        glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);

        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));



        
        // Load textures
        
        glGenTextures(2, textures);

        int width, height;
		short* image;
		//CImg<unsigned short> temp("1_AXIAL0.png");
		CImg<short> texture = CImg<short>(2, 2, 1, 1, 32767);//("1_AXIAL0.png");
		texture(0, 0) = 0;
		texture(1, 1) = 0;
		width = texture._width;
		height = texture._height;
        glActiveTexture(GL_TEXTURE0);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
		image = texture._data;
        if (!image)
        {
        printf("image is null  \n");
        }
		int i1= glGetError();
        glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, GL_SHORT, image);
		int i2 = glGetError();
		std::cout << i1 << "  " << i2 << std::endl;
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

}

void init()
{
    //init_fix();
    SetupShader();

    InitVBO();

    glClearColor(0.0, 0.0, 0.0, 1.0);


}

void display()
{
    static int num_frame = 0;
    num_frame++;
    std::cout << "num_frame: " << num_frame << std::endl;
    //glClear(GL_COLOR_BUFFER_BIT);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glUseProgram(programHandle);
    glUniform1i(glGetUniformLocation(programHandle, "texPuppy"), 0);
    //glUniform1i(glGetUniformLocation(programHandle, "texKitten"), 0);
    glBindVertexArray(vaoHandle);

    glEnable(GL_TEXTURE_2D);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    glutSwapBuffers();

}

void reshape(int w, int h)//这个函数其实是可以简化的，具体的简化参看以前的程序
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glLoadIdentity();
    if (w <= h)
        glOrtho(-1, 1, -1*(GLfloat)h / (GLfloat)w,
        1*(GLfloat)h / (GLfloat)w, -1.0, 1.0);
    else
        glOrtho(-1*(GLfloat)w / (GLfloat)h,
        1*(GLfloat)w / (GLfloat)h, -1, 1, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    
}

int main(int argc, char** argv) {

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(800, 800);
    glutCreateWindow("第二讲demo");

    GLenum err = glewInit();  // 前面运行了glut*的一系列函数，已经获得了opengl的context，所以这里不会出错，读者可以试试在main的开始就调用这句会怎样  
    if (err != GLEW_OK) {
        fprintf(stderr, "%s\n", glewGetErrorString(err));
        return  -1;
    }
    //glutReshapeFunc(reshape);
    const GLubyte* name = glGetString(GL_VENDOR); //返回负责当前OpenGL实现厂商的名字
    const GLubyte* biaoshifu = glGetString(GL_RENDERER); //返回一个渲染器标识符，通常是个硬件平台
    const GLubyte* OpenGLVersion = glGetString(GL_VERSION); //返回当前OpenGL实现的版本号
    const GLubyte* gluVersion = gluGetString(GLU_VERSION); //返回当前GLU工具库版本
    const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
    printf("OpenGL实现厂商的名字：%s\n", name);
    printf("渲染器标识符：%s\n", biaoshifu);
    printf("OpenGL实现的版本号：%s\n", OpenGLVersion);
    printf("OGLU工具库版本：%s\n", gluVersion);
    printf("GLSL版本：%s\n", glslVersion);
    GLint max;
    glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max);
    bool fix =false;
    if (fix)
    {
        init_fix();

        glutDisplayFunc(display_fix);
    }
    else
    {
        init();
        glutDisplayFunc(display);
    }

    
    glutMainLoop();
    return 0;
}